(* Fixed Length Codes *)

\(minima = "mathematics with mathematica"; 

    chars = Characters[minima]\)

alphabet = Union[chars]

Length[alphabet]

fixedcodes = Table[IntegerDigits[i, 2, 4], {i, 10}]

Thread[{{a, b, c}, {1, 2, 3}}]

Thread[f[{a, b, c}, {1, 2, 3}]]

Thread[f[{a, b, c}, c, {1, 2, 3}]]

Thread[{a, b, c} -> {1, 2, 3}]

Transpose[{{a, b, c}, {1, 2, 3}}]

Map[(Rule @@ # )& , Transpose[{{a, b, c}, {1, 2, 3}}]]

characterrules = Thread[alphabet -> fixedcodes]

InputForm[characterrules = Thread[alphabet -> fixedcodes]]

coderules = Thread[fixedcodes -> alphabet]

InputForm[coderules = Thread[fixedcodes -> alphabet]]

codify[c_String] := c /. characterrules

TableForm[{InputForm[#], {codify[#]}}& /@ alphabet]

TableForm[{InputForm[#], {codify[#]}}& /@  chars]

encodeminima [codefun_,  minima_] := 
      Flatten[codefun /@ Characters[minima]]

enminima = encodeminima[codify,  minima]

Length[enminima]

deminima = Partition[enminima, {4}]  /. coderules

StringJoin @@ deminima

\(encodeminima\ [minima_String] := 
      Module[{chars, \ alphabet, \ fixedcodes, \ characterrules, \ coderules, 
          \ codify, enminima}, 

        codify[c_String] := Module[{}, c\  /. \ characterrules]; 

        chars = Characters[minima]; 
alphabet = Union[chars]; 
        len = Length[alphabet]; 

        fixedcodes = 
          Table[IntegerDigits[i, 2, Ceiling[Log[2, len]]], {i, len}]; 

        characterrules = Thread[alphabet -> fixedcodes]; 

        coderules = Thread[fixedcodes -> alphabet]; 

        enminima = Flatten[codify\ /@\ Characters[minima]]; 
        
{enminima, \ coderules}]\)

\(decodeminima[codedminima_List, coderules_] := 
      Module[{deminima\ }, 

        deminima = Partition[codedminima, {4}]\  /. coderules; \ 
        StringJoin\ @@\ deminima]\)

minima = "mathematics with mathematica"

encodeminima[minima]

decodeminima[%[[1]], %[[2]]]

Clear["`*"]

Names["`*"]

(* huffman codes *)

\(minima = "mathematics with mathematica"; 

    chars = Characters[minima]\)

alphabet = Union[chars]

frequences = {Count[chars, #],  #}& /@ alphabet

frequences = Sort[frequences]

Take[frequences, 2]

Transpose[%]

MapAt[Plus  @@ # &,  %, {1}]

Union[Drop[frequences, 2], {%}]

\(combine[x_] := 
      If[Length[x]\  < \ 2, x, 
		
        Union[Drop[x, 2], {
            MapAt[Plus\ @@\ #\ &, \ Transpose[Take[x, 2]], {1}]}]]\)

frequences = combine[frequences]

frequences = combine[frequences]

frequences = combine[frequences]

frequences = combine[frequences]

FixedPoint[combine, frequences]

tree = %[[1, 2]]

Position[tree, "h"]

%[[1]] - 1

Position[tree, "w"]

%[[1]] - 1

huffmancode[c_String] := Position[tree, c][[1]] - 1

TableForm[{InputForm[#],  {huffmancode[#]}}& /@ alphabet]

encodeminima [codefun_,  minima_] := 
      Flatten[codefun /@ Characters[minima]]

enminima = encodeminima[huffmancode,  minima]

Length[enminima]

{1, 1, 0, 1, 1} + 1

Extract[tree, %]

Extract2[list_, {indices__}] := list[[indices]]

{1, 1, 0, 1, 1} + 1

Extract2[tree, %]

code2char[tr_List,  pos_List] := Extract[tr, pos + 1]

code2char[tree, {0, 1, 0}]

\(decodeminima[huftree_List, enminima_List] := 
      Module[{enm = enminima, \ nextcharlist = {}, deminima = ""}, 
	
        While\ [\ enm\  =!= {}, \ 
			
          AppendTo[nextcharlist, \ enm[\([1]\)]]; 
				enm = Rest[enm]; 
          
		If[StringQ[code2char[huftree, \ nextcharlist]], 
			
            deminima\  = \ deminima\ <>\ code2char[huftree, \ nextcharlist]; 
            nextcharlist = {}]]; deminima]\)

decodeminima[tree, enminima]

\(trans[state_List, \ input_Integer] := 
	
      With[{newstate = Append[state, \ input]}, 
		
        If[StringQ[code2char[tree, \ newstate]], 
			
          decoded\  = \ decoded\ <>\ code2char[tree, \ newstate]; {}, 
			
           (*else*) \ newstate\ ]]\)

decoded = "";

FoldList[trans, {}, {1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1}]

decoded

InputForm[decoded]

decoded = "";

Fold[trans, {}, encodedtext]

InputForm[decoded]

othertree = tree

Clear[trans]\(trans[state_List, \ input_Integer] := 
	
      With[{str = state[\([1]\)], \ newpos = Append[state[\([2]\)], \ input], 
          tree = state[\([3]\)]}, 
		
        If[StringQ[code2char[tree, \ newpos]], 

          			{str\ <>\ code2char[tree, \ newpos], {}, tree}, 

          			{str\ , newpos, \ tree}\ ]]\)

{"", {}, othertree}

FoldList[trans, {"", {}, tree},  {1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0}]
          // InputForm

Fold[trans, {"", {}, tree}, 
       {1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1}]

Fold[trans, {"", {},  tree},  encodedtext]

othertreetree

\(Clear[huffmandecode]; 

    huffmandecode[tr_List, \ input_List] := 
      \(Fold[trans, {"", {}, tr}, input]\)[\([1]\)]\)

huffmandecode[othertree,  encodedtext]

tree = othertree

Clear[trans]\(trans[tr_List] := 
	
      Function[{state, \ input}, 
	
        With[{str = state[\([1]\)], \ 
            newpos = Append[state[\([2]\)], \ input]}, 
		
          If[StringQ[code2char[tr, \ newpos]], 

            			{str\ <>\ code2char[tr, \ newpos], {}}, 

            			{str\ , newpos}\ ]]]\)

trans[tree]

\(Clear[huffmandecode]; 

    huffmandecode[tr_List, \ input_List] := 
      \(Fold[trans[tr], {"", {}}, input]\)[\([1]\)]\)

othertree = tree

Clear[tree]

tree = othertree

huffmandecode[tree,  encodedtext]